/*
 * ForceTransmission.h
 *
 *      Author: Jerome RD Soine and Christoph A Brand
 *      Institution: Schwarz goup, Institute for Theoretical Physics, Heidelberg University, Germany
 */

#ifndef FORCETRANSMISSION_H_
#define FORCETRANSMISSION_H_

#include <vector>
#include "shape/Shape.h"
#include "shape/Circle.h"
#include <cmath>
#include <iostream>
#include <stdlib.h>

using namespace std;

/*!
 *  \brief Object that defines the shape and magnitude of a single traction spot. Defines the interface between cell and substrate models.
 *
 *  An entity of this Object describes a single traction transmission object. It contains a pointer
 *  to a Shape object and a force vector that determines the direction and magnitude (Oh yeah!) of applied traction.
 */

class ForceTransmission{
private:
	/*!
	 * Pointer to Shape object
	 */
	Shape* shape;
	/*!
	 * Force vector
	 */
	vector<double> force;

public:
	/*!
	 * Constructor for empty force transmission object.
	 */
	ForceTransmission() {shape = new Circle(vector<double>(2,0),1);};
	/*!
	 * Constructs ForceTransmission object with given SHAPE and FORCE.
	 */
	ForceTransmission(vector<double> FORCE, Shape * SHAPE) { force = FORCE; shape = SHAPE; };
	/*!
	 * Destructor for ForceTransmission object.
	 */
	~ForceTransmission(){ delete shape; };
	/*!
	 * Returns pointer to Shape associated with the ForceTransmission object.
	 */
	Shape * get_shape() { return shape; };
	/*!
	 * Set pointer to Shape associated with the ForceTransmission object.
	 */
	void set_shape(Shape * SHAPE) { shape = SHAPE; };
	/*!
	 * Returns Force associated with ForceTransmission object.
	 */
	vector<double> get_force() { return force; };
	/*!
	 * Set Force associated with ForceTransmission object.
	 */
	void set_force(vector<double> FORCE) { force = FORCE; };

	double get_force_magnitude() {
		double mag_square = 0;
		for(unsigned int i=0; i<force.size(); i++){
			mag_square += force[i] * force[i];
		}
		return sqrt(mag_square);
	};

	/*!
	 * Search for spatial range in x-direction based on shape centers
	 */
	static vector<double> get_x_range (vector<ForceTransmission*> fts) {return get_range(fts,0);};
	/*!
	 * Search for spatial range in y-direction based on shape centers
	 */
	static vector<double> get_y_range (vector<ForceTransmission*> fts) {return get_range(fts,1);};
	/*!
	 * Search for spatial range of shapes based on center positions along direction comp.
	 */
	static vector<double> get_range(vector<ForceTransmission*> fts, unsigned int comp)
	{
		if(comp>1) {cout << "ERROR: FORECTRANSMISSION->get_range: component index > 1" << endl; exit(0);}
		double max=fts[0]->get_shape()->get_center()[comp], min=fts[0]->get_shape()->get_center()[comp];
		for(unsigned int i=1;i<fts.size();i++)
		{
			vector<double> center = fts[i]->get_shape()->get_center();
			if(center[comp]<min)
				min = center[comp];
			if (center[comp]>max)
				max = center[comp];
		}
			vector<double> range (2,0);
			range[0] = min;
			range[1] = max;
			return range;
	};
	/*!
	 * Return maximal area appearing in an array of ForceTransmissions.
	 */
	static double get_max_area(vector<ForceTransmission*> fts)
	{
		double max_area=fts[0]->get_shape()->get_area();
		for (unsigned int i = 1; i < fts.size(); ++i) {
			double tmp_area = fts[i]->get_shape()->get_area();
			if(tmp_area>max_area)
				max_area = tmp_area;
		}
		return max_area;
	};
	/*!
	 * Return minimal area appearing in an array of ForceTransmissions.
	*/
	static double get_min_area(vector<ForceTransmission*> fts)
	{
		double min_area=fts[0]->get_shape()->get_area();
		for (unsigned int i = 1; i < fts.size(); ++i) {
			double tmp_area = fts[i]->get_shape()->get_area();
			if(tmp_area<min_area)
				min_area = tmp_area;
		}
		return min_area;
	};
	/*!
	 * Return mean shape area for an an array of ForceTransmissions.
	*/
	static double get_mean_area(vector<ForceTransmission*> fts)
	{
		double total_area = 0;
		for (unsigned int i = 1; i < fts.size(); ++i) {
			total_area += fts[i]->get_shape()->get_area();
		}
		return total_area/fts.size();
	};
	/*!
	 * Return vector with number of FA in the neighborhood of radius i of for
	 * vector of ForceTransmission objects.
	 */
	static vector<int> get_number_of_neighbors_list (vector<ForceTransmission*> fts, double radius)
	{
		vector<int> neighbor_list;
		for (unsigned int i = 0; i < fts.size(); ++i) {
			neighbor_list.push_back(get_number_of_neighbors(fts,i,radius));
		}
		return neighbor_list;
	 }
	 /*!
	  * Return number of neighbors for a given FA index.
	  */
	static int get_number_of_neighbors (vector<ForceTransmission*> fts, unsigned int index ,double radius)
	{
		int neighbors = 0;
		double x1 = fts[index]->get_shape()->get_center()[0];
		double y1 = fts[index]->get_shape()->get_center()[1];
		for(unsigned int j = 0; j < fts.size(); ++j){
					double x2 = fts[j]->get_shape()->get_center()[0];
					double y2 = fts[j]->get_shape()->get_center()[1];
					if( index!=j && ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<=radius*radius))
							neighbors++;
		}
		return neighbors;
	}

};


#endif /* FORCETRANSMISSION_H_ */
